# -*- coding = utf-8 -*-
# @Time : 2020/7/11 9:32
# @Author : gxm


import cv2
import cv2 as cv
import numpy as np

# 车牌定位与切割



# 预处理图片
def img_preprocess(img):
    # 规范图片格式
    m=400 * img.shape[0] / img.shape[1]
    img=cv2.resize(img,(400,int(m)),interpolation=cv2.INTER_CUBIC)
    # 图片处理，易于识别车牌位置
    gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    stretchedimg=stretching(gray_img)

    r=15
    h=w=r*2+1
    kernel=np.zeros((h,w),np.uint8)
    cv2.circle(kernel,(r,r),r,1,-1)
    openingimg=cv2.morphologyEx(stretchedimg,cv2.MORPH_OPEN,kernel)

    strtimg=cv2.absdiff(stretchedimg,openingimg)
    binaryimg=allbinaryzation(strtimg)
    canny=cv2.Canny(binaryimg,binaryimg.shape[0],binaryimg.shape[1])

    kernel=np.ones((5,23),np.uint8)
    closingimg=cv2.morphologyEx(canny,cv2.MORPH_CLOSE,kernel)
    openingimg=cv2.morphologyEx(closingimg,cv2.MORPH_OPEN,kernel)
    kernel=np.ones((11,6),np.uint8)
    openingimg=cv2.morphologyEx(openingimg,cv2.MORPH_OPEN,kernel)

    rect=plate_locate(openingimg, img)
    return rect,img

# 图片操作：图像拉伸函数
def stretching(img):
    maxi=float(img.max())
    mini=float(img.min())
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            img[i,j]=(255/(maxi-mini)*img[i,j]-(255*mini)/(maxi-mini))
    return img

# 图片操作：二值化处理函数
def allbinaryzation(img):
    maxi=float(img.max())
    mini=float(img.min())
    x=maxi-((maxi-mini)/2)
    ret,thresh=cv2.threshold(img,x,255,cv2.THRESH_BINARY)
    return thresh



# 定位车牌位置
def plate_locate(img, afterimg):
    contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    block=[]
    for c in contours:
        r=find_rectangle(c)
        a=(r[2]-r[0])*(r[3]-r[1])
        s=(r[2]-r[0])/(r[3]-r[1])
        block.append([r,a,s])
    # block=sorted(block,key=lambda b: b[1])[-3:]
    maxweight,maxindex=0,-1

    for i in range(len(block)):
        b=afterimg[block[i][0][1]:block[i][0][3],block[i][0][0]:block[i][0][2]]
        hsv=cv2.cvtColor(b,cv2.COLOR_BGR2HSV)
        lower=np.array([100,50,50])
        upper=np.array([140,255,255])
        mask=cv2.inRange(hsv,lower,upper)
        w1=0
        for m in mask:
            w1+=m/255
        w2=0
        for n in w1:
            w2+=n
        if w2>maxweight:
            maxindex=i
            maxweight=w2
    return block[maxindex][0]

# 在处理后的图片中寻找矩形，易于定位车牌位置
def find_rectangle(contour):
    y,x=[],[]
    for p in contour:
        y.append(p[0][0])
        x.append(p[0][1])
    return [min(y),min(x),max(y),max(x)]



# 根据定位去除原图片其他部分
def plate_cut(afterimg, rect):
    rect[2]=rect[2]-rect[0]
    rect[3]=rect[3]-rect[1]
    rect_copy=tuple(rect.copy())
    # cv2.imshow("lj",afterimg)
    # print("rect_copy",rect_copy)
    mask=np.zeros(afterimg.shape[:2],np.uint8)
    bgdModel=np.zeros((1,65),np.float64)
    fgdModel=np.zeros((1,65),np.float64)
    cv2.grabCut(afterimg,mask,rect_copy,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
    mask2=np.where((mask==2)|(mask==0),0,1).astype('uint8')
    img_show=afterimg*mask2[:,:,np.newaxis]
    return img_show

# 车辆图片的初次切割
def img_firstmake(img):

    rect, afterimg = img_preprocess(img)
    rect[0]-=5
    rect[1]-=5
    rect[2]+=5
    rect[3]+=5
    cv2.rectangle(afterimg, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0), 2)
    # cv2.imshow("lj", afterimg)
    # print(rect)
    cutimg = plate_cut(afterimg, rect)
    # cv2.imshow('cutimg1', cutimg)
    # cv2.waitKey(0)
    return cutimg





# 车辆图片的精切割
def img_finalmake(img):
    img_resize = cv.resize(img, (640, 480), )
    img_gaus = cv.GaussianBlur(img_resize, (5, 5), 0)
    img_med = cv.medianBlur(img_gaus, 5)
    img_hsv = cv.cvtColor(img_med, cv.COLOR_BGR2HSV)
    lower_blue = np.array([100, 40, 50])
    higher_blue = np.array([140, 255, 255])
    mask = cv.inRange(img_hsv, lower_blue, higher_blue)
    img_res = cv.bitwise_and(img_med, img_med, mask=mask)


    img_gray_h = cv.cvtColor(img_res, cv.COLOR_BGR2GRAY)
    ret1, img_thre_h = cv.threshold(img_gray_h, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)


    img_gray_s = cv.cvtColor(img_med, cv.COLOR_BGR2GRAY)


    img_sobel_x = cv.Sobel(img_gray_s, cv.CV_32F, 1, 0, ksize=3)
    img_sobel_y = cv.Sobel(img_gray_s, cv.CV_32F, 0, 1, ksize=3)
    img_ab_y = np.uint8(np.absolute(img_sobel_y))
    img_ab_x = np.uint8(np.absolute(img_sobel_x))
    img_ab = cv.addWeighted(img_ab_x, 0.5, img_ab_y, 0.5, 0)

    img_gaus_1 = cv.GaussianBlur(img_ab, (5, 5), 0)


    ret2, img_thre_s = cv.threshold(img_gaus_1, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)


    img_1 = np.zeros(img_thre_h.shape, np.uint8)
    height = img_resize.shape[0]
    width = img_resize.shape[1]
    for i in range(height):
        for j in range(width):
            h = img_thre_h[i][j]
            s = img_thre_s[i][j]
            if h == 255 and s == 255:
                img_1[i][j] = 255
            else:
                img_1[i][j] = 0



    kernel = np.ones((14, 18), np.uint8)
    img_close = cv.morphologyEx(img_1, cv.MORPH_CLOSE, kernel)
    img_med_2 = cv.medianBlur(img_close, 5)



    regions = []
    list_rate = []
    img_input = img_med_2.copy()
    contours, hierarchy = cv.findContours(img_input, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

    for contour in contours:

        area = cv.contourArea(contour)

        if area < 2000:
            continue

        epslion = 1e-3 * cv.arcLength(contour, True)
        approx = cv.approxPolyDP(contour, epslion, True)

        rect = cv.minAreaRect(contour)
        box = cv.boxPoints(rect)
        box = np.int0(box)
        height = abs(box[0][1] - box[2][1])
        width = abs(box[0][0] - box[2][0])
        ratio = float(width) / float(height)
        if ratio > 2 and ratio < 5:
            regions.append(box)
            list_rate.append(ratio)

    print('[INF0]:Detect %d license plates' % len(regions))  # 输出疑似车牌图块的数量
    index = get_satifyestrect(list_rate)
    region = regions[index]
    img_2 = np.zeros(img_resize.shape, np.uint8)
    img_2 = img_resize.copy()
    cv.drawContours(img_2, [region], 0, (0, 255, 0), 2)
    Xs = [i[0] for i in region]
    YS = [i[1] for i in region]
    x1 = min(Xs)
    x2 = max(Xs)
    y1 = min(YS)
    y2 = max(YS)
    height_1 = y2 - y1
    width_1 = x2 - x1
    img_crop = img_resize[y1:y1 + height_1, x1:x1 + width_1]

    img_hsv_1 = cv.cvtColor(img_crop, cv.COLOR_BGR2HSV)  # hsv模型
    lower_blue_1 = np.array([100, 90, 90])
    higher_blue_1 = np.array([140, 255, 255])
    mask_1 = cv.inRange(img_hsv_1, lower_blue_1, higher_blue_1)  # 掩膜操作
    img_res_1 = cv.bitwise_and(img_crop, img_crop, mask=mask_1)

    img_gray_1 = cv.cvtColor(img_res_1, cv.COLOR_BGR2GRAY)  # 转换了灰度化
    ret3, img_thre_1 = cv.threshold(img_gray_1, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)

    height_2 = img_thre_1.shape[0]  # 获得行数
    width_2 = img_thre_1.shape[1]  # 获得列数
    white_min = []
    white_max = []
    a = 0
    b = 0

    for i in range(height_2):
        for j in range(width_2):
            h = img_thre_1[i, j]
            if h == 255:
                a = j
                white_min.append(a)
                break
    a = min(white_min)
    for q in range(height_2 - 1, -1, -1):
        for w in range(width_2 - 1, -1, -1):
            ps = img_thre_1[q, w]
            if ps == 255:
                b = w
                white_max.append(b)
                break
    b = max(white_max)
    white_min1 = []
    white_max1 = []
    c = 0
    d = 0

    for i in range(width_2):
        for j in range(height_2):
            h = img_thre_1[j, i]
            if h == 255:
                c = j
                white_max1.append(c)
                break
    c = min(white_max1)
    for q in range(width_2 - 1, -1, -1):
        for w in range(height_2 - 1, -1, -1):
            ps = img_thre_1[w, q]
            if ps == 255:
                d = w
                white_min1.append(d)
                break
    d = max(white_min1)
    img_cut = img_crop[c:d, a:b]
    return img_cut

# 寻找最符合车牌特征的矩形
def get_satifyestrect(list_rate):
    for index, key in enumerate(list_rate):
        list_rate[index] = abs(key - 3)

    index = list_rate.index(min(list_rate))
    return index

# 运行切割车牌模块
def Plate_cut_run(img):
    img_run=img_firstmake(img)
    img_runplus=img_finalmake(img_run)
    return img_runplus


if __name__ == "__main__":
    img = cv2.imread("C:\\Users\\19372\PycharmProjects\\demo_1\\demo2\\pict\\5.jpg")
    # imgplus = img_firstmake(img)
    # cv.imshow("plate", imgplus)
    # cv.waitKey(0)
    # img_p = img_finalmake(imgplus)
    # print(img_p)
    img_p=Plate_cut_run(img)
    cv.imshow("plate", img_p)
    cv.waitKey(0)
